#include "firmware.h"


#define TRIGGER_MANUAL        0
#define TRIGGER_CMP           1
#define TRIGGER_CMP_INVERTED  2
//#define TRIGGER_SINGLE_EDGE   3
#define TRIGGER_MULTI_EDGE    4


volatile char IsrState = 3;
volatile unsigned int IsrMinimalPreSamplingCountDown;
volatile unsigned int IsrExtraPreSamplingCountDown;
volatile unsigned int IsrSamplingPagesCountDown;
volatile unsigned int IsrPageCounter;
volatile char TriggerTrue;

SIGNAL(TIMER0_OVF_vect)
{          
   // keep track of 4040's
   IsrPageCounter++;

   // keep track of sample data
   switch (IsrState) {
      case 0 : {
         // wait until we have the minimal amount of pre-samples
         IsrMinimalPreSamplingCountDown--;
         if (IsrMinimalPreSamplingCountDown == 0) IsrState = 1;
         break;
      }
      case 1 : {
         // wait for trigger
         if (TriggerTrue) IsrState = 2;
   
         // count extra pre-samples we collect untill memory is full
         if (IsrExtraPreSamplingCountDown > 0) IsrExtraPreSamplingCountDown--;
         break;
      }
      case 2 : {
         // Collect requested nr of samples
         IsrSamplingPagesCountDown--;
         if (IsrSamplingPagesCountDown == 0) {
            // Stop sampling
            TCCR1A=0x00;
            TCCR1B=0x00;		//Stop Timer1
            TCCR0B=0x00;		//Stop Timer0
            IsrState = 3;
         }
         break;
      }
      default: {  // this includes state 3, done
         // wait forever
         break;
      }      
   }
}



// Trigger - wait for trigger to happen.
void GetSamples(unsigned int TriggerMode, unsigned int Param1, unsigned int Param2)
{
   //-------------------------
   // Step 1 : start sampling.
   //-------------------------      
   
                  
   // init counters       
   IsrMinimalPreSamplingCountDown   = ConfigRegisters[REG_PRESAMPLE_SIZE];
   IsrExtraPreSamplingCountDown     = 65535;
   IsrSamplingPagesCountDown        = ConfigRegisters[REG_SAMPLE_SIZE];         
                  
   // open gate to memory
   GateEnable(true);     

   // reset (4040) address counters
   CounterResetPulse();
   IsrPageCounter = 0;

   // setup T0 to follow address counters & enable interrupt
   TCNT0=0;                              
   PinSet(TIMSK0, TOIE0);   
   TCCR0B=0x07;   // clock from pin T0, rising edge
   
   //------------------------------------------------------------
   // setup Timer1 to generate sample clock
   //------------------------------------------------------------
   // Clear Timer on Compare with OCR1A (CTC mode, WGM1 = 0100)
   // Toggle OC1A on match (COM1A = 01)
   // Prescaler off, clock = Fosc / 2 (CS1=001)
   //------------------------------------------------------------
   TCCR1A=0x40;   
	TCCR1B=0x09;   
	OCR1A = ConfigRegisters[REG_SAMPLE_RATE] - 1;  // clock rate = Fosc / 2 / (1 + OCR1A) (note: OCR1A = 0 is valid!)   

   // Set state machine to pre-sampling      
   TriggerTrue = false;
   IsrState = 0;                       
   while (IsrState == 0) {}; // wait until presampling ends
   
   //-------------------------------------                                          
   // Step 2 : wait for requested trigger.
   //-------------------------------------

   // first, trigger        
   switch(TriggerMode) {
      case TRIGGER_MANUAL :
         // start immediately 
      break;

      case TRIGGER_CMP :  
         // Match = trigger wait for certain state to occure
         // cmp mismatch - first wait until trigger-condition is *not* met
         while ((PINC & Param1) != Param2) {} 
         
         // cmp match - wait for trigger-condition
         while ((PINC & Param1) == Param2) {} 
         
      break;

//      case TRIGGER_CMP_INVERTED :
//         // Matc Inverted - wait for a certain state to end (typical: idle state) 
//         // cmp match - first make sure we're not in the idle state
//         while ((PINC & Param1) == Param2) {} 
//         
//         // cmp mismatch - wait for idle state to end 
//         while ((PINC & Param1) != Param2) {} 
//         
//      break;                                      
         
         
      case TRIGGER_MULTI_EDGE :
         // Multiple edges are defined. If any of those occures, we have a trigger.
         // Note: this is a rather complex (= time consuming) function, so realy short 
         //       spikes might be missed...
         //    

         unsigned char NewSample, PrevSample, Edges;   
         unsigned char BitMask         =  Param1;
         unsigned char EdgeLevelMask   = Param2;
  
         PrevSample = PINC & BitMask;
         for (;;) {
            NewSample = PINC & BitMask;      // get sample & mask irrelevant lines
            Edges = NewSample ^ PrevSample;  // determine edges  
            if (Edges == 0) continue;        // no edges on relevant pins -> next
            PrevSample = NewSample;          // save sample
            
            // check if Edge is on a line that has the right level now (= edge in right direction)
            if ((Edges & (NewSample ^ EdgeLevelMask)) == 0) continue;   // no
               
            // YES -> we're done
            break;
                                             
         }         
      break;
   }

   // Store the trigger point.
   ConfigRegisters[REG_START_OFFSET] = TCNT0;  
   ConfigRegisters[REG_START_PAGE] = IsrPageCounter;                           
   TriggerTrue = true;  // indicate ISR we're now collecting post-trigger data
   if (TCNT0 <  ConfigRegisters[REG_START_OFFSET]) {
      // there was a wrap-around, so we might have the wrong start_page
      ConfigRegisters[REG_START_PAGE] = IsrPageCounter - 1;
   }
   // report we've started to sample
   MsgOpen('S');
   MsgParam(0x10);
   MsgClose();
                                             
   //----------------------------------------                                             
   // Step 3 : wait for sampling to complete.
   //----------------------------------------
                                             
   long int Blink = 0;                                          
   while (IsrState != 3) {
      // aquiring data, blink led
      Blink ++;
      RedLed(Blink > 100000);
      if (Blink > 200000) Blink = 0;         
   }
   
   // close gate to memory
   GateEnable(false);     

   // report we're done sampling
   MsgOpen('S');
   MsgParam(0x20);
   MsgClose();
} 